home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
os2
/
vsoup11.zip
/
news.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-02
|
43KB
|
1,697 lines
// $Id: news.cc 1.23 1996/09/02 13:25:10 hardy Exp $
//
// This progam/module was written by Hardy Griech based on ideas and
// pieces of code from Chin Huang (cthuang@io.org). Bug reports should
// be submitted to rgriech@ibm.net.
//
// This file is part of soup++ for OS/2. Soup++ including this file
// is freeware. There is no warranty of any kind implied. The terms
// of the GNU Gernal Public Licence are valid for this piece of software.
//
// Get news from NNTP server.
//
// rg270596:
// - multithreading support for OS/2
//
// Und nun mal ein paar Erfahrungen mit multithreading (in diesem Zusammenhang):
// -----------------------------------------------------------------------------
//
// Probleme mit CHANGI:
// - die ursprüngliche CHANGI Version "spann" bei vielfachem Zugriff
// Update nach changi09m brachte erhebliche Erleichterung
// - nntp-NEXT tut nicht, wenn gleichzeitig ein Artikel gelesen wird,
// oder wenn mehrere NEXTs unterwegs sind (könnte CHANGI-Problem sein)
// 120696: war eher meine Blödheit und hatte u.U. was mit den Signalen zu tun...
// Wahrscheinlich braucht der NEXT recht lange und der entsprechende
// gets() wurde dann mit hoher Wahrscheinlichkeit durch ein Signal
// unterbrochen...
//
// Probleme mit EMX-GCC09a:
// - das signal-handling scheint fragwürdig (signal muß aber abgefangen werden...):
// - nextchar in socket (wird durch recv/read gemacht) kommt u.U. mit EINTR
// zurück - doch wie setze ich dann wieder auf???
// - _beginthread kommt u.U. mit EINVAL zurück, was jedoch ebenso auf einen
// unterbrochenen Aufruf schließen läßt (d.h. Fehlerauswertung nicht vollständig)
// --> Signale nicht dazu verwenden, um die Beendigung eines Threads anzuzeigen,
// sondern nur in absoluten Notfällen!!!
// - einmal (?) hatte ich im (durch Semaphor geschützten) StdOut einen größeren
// Block doppelt. Das Programm hat den Block unmöglich (?) produzieren können,
// also kommt nur EMX-GCC in Frage bzw. das OS
// - new/delete können nicht selbst definiert werden
// - wie komme ich bitte an _threadid ? (stddef.h war nicht für C++)
// - unlink steht nicht in stdio.h, sondern unistd.h
// - tmpfile() / tempnam() durch Semaphor geschützt ??
// --> hätte ich Zugriff, würde ich sofort nach 09b updaten!!!
//
// Hausgemachte Probleme:
// - ein mehrfacher Request von einem MutexSemaphor in EINEM Thread hält diesen
// NICHT an. Nur ein anderer Thread kann das Semaphor nicht mehr anfordern...
// - Zustandsmaschine war durch 'mode reader' nicht mehr korrekt (es wurde schon ein
// 'waiting' angezeigt, obwohl noch 'init' war...)
// - in nntpMtGetFinished wurde der Zustand zweimal abgefragt und dann noch in der
// Reihenfolge 'finished'?, 'running'?. Dieser Übergang wird aber in einem Thread
// gemacht -> Thread war u.U. noch nicht 'finished', aber auch nicht mehr 'running'.
// Dies ergibt ein leicht inkonsistentes Bild der Zustände!
// - wird ein Zähler im Thread hochgezählt und muß hinterher ausgewertet
// werden, so empfiehlt sich mindestens ein Semaphor (vielleicht auch noch
// volatile) (bytesRcvd)
// - die Threads müssen auch einen Signal-Handler für z.B. SIGPIPE haben, sonst
// gibt es bei Abbruch u.U. einen doppelten Fehler! (das kommt daher, wie ein
// Programm abgebrochen wird)
// - ein Event-Semaphor will auch zurückgesetzt werden! Die 'Kinder' laufen sonst
// echt Gefahr zu verhungern...
// - stream-I/O muß konsequent durch MuxSema geschützt werden (ein bißchen Disziplin
// bitte)
// - regexp hat statische Variablen
// - um Klassen, die was mit Listen oder so zu tun haben, am besten auch ein
// individuelles Semaphor legen
// - stimmt der makefile nicht, und es wird ein Datentyp geändert, so kommt es
// klarerweise zu seltsamen Effekten (die Objekte werden nicht neu angelegt, etc.)
// - beachte Zuweisung eines 'char' von 0xff (== -1) an einen int!!!
//
//
// um das Signal-Problem hinzubekommen einfach definieren!
// - nextchar() in socket liefert bei read bzw recv EINTR zurück
// - _beginthread wird u.U. auch unterbrochen (recht unwahrscheinlich, aber wahr)
//
//#define SIGNAL_PROBLEM
//
// Testroutine, die die Angelegenheit ein bißchen behindern soll, einbinden
//
//#define INSERT_MTTEST
#include <assert.h>
#include <process.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "areas.hh"
#include "global.hh"
#include "kill.hh"
#include "mts.hh"
#include "news.hh"
#include "newsrc.hh"
#include "nntp.hh"
#include "nntpcl.hh"
#include "socket.hh"
static TSemaphor divSema;
static TEvSemaphor threadFinito;
static TEvSemaphor disconnectDone;
static TProtCounter artsRcvd; // articles received...
static TProtCounter artsKilled; // articles killed...
static TKillFile killF; // kill file handling
static TProtCounter getArt_artRcvd; // globals for mtGetArticle()
static long getArt_grpHi; // (I hate those f* globals -> restructure)
static int doingProcessSendme; // currently doing processSendme
static long catchupNumKeep;
//
// thread states (init must be 0)
// starting is for debugging and not absolutely required...
//// (are static vars initialized to zero ?)
//
enum NntpStates { init,connecting,failed,waiting,starting,running,runningspecial };
//
// these are the thread connections to the news server
//
#ifndef INSERT_MTTEST
static TNntp nntp[ MAXNNTPTHREADS ]; // no pointer (because of imlicit destructor)
static NntpStates nntpS[MAXNNTPTHREADS ] = {init};
#else
static TNntp nntp[ MAXNNTPTHREADS+1 ];
static NntpStates nntpS[MAXNNTPTHREADS+1 ] = {init };
#define TESTTHREAD (MAXNNTPTHREADS)
#endif
//--------------------------------------------------------------------------------
//
// utility functions
//
#ifdef SIGNAL_PROBLEM
static void signalHandler( int sig )
//
// nur dazu da, um sleep abzubrechen
//
{
signal( sig, SIG_ACK );
} // signalHandler
#endif
#if defined(DEBUG) || defined(TRACE_ALL) || defined(TRACE) || defined(TRACE_ALL)
static void printThreadState( const char *pre, int maxNo=maxNntpThreads )
{
int i;
char b[100];
assert( maxNo <= maxNntpThreads );
sprintfT( b,"%s: ",pre );
for (i = 0; i < maxNo; i++) {
switch (nntpS[i]) {
case init:
strcat(b,"[i]");
break;
case connecting:
strcat(b,"[c]");
break;
case starting:
strcat(b,"[s]");
break;
case waiting:
strcat(b,"[w]");
break;
case running:
strcat(b,"[r]");
break;
case runningspecial:
strcat(b,"[R]");
if (maxNo < maxNntpThreads)
++maxNo;
break;
case failed:
strcat(b,"[E]");
if (maxNo < maxNntpThreads)
++maxNo;
break;
}
}
printfT( "%s\n",b );
}
#endif
static int killArticleQ( const char *groupName, const char *headerLine )
//
// this is a hook function for TNntp...
//
{
return killF.matchLine( groupName,headerLine );
} // killArticleQ
static void processXref( const char *s )
//
// Process an Xref line.
// format: 'Xref: '<host-name> <grp-name[: ]grp-num>(\b<grp-name[: ]grp-num>)*
// - s points behind 'Xref: '
// - \b may be blank or \t
//
// rg260596: the new version works with sscanf (before strtok). Hopefully this version
// is ok for multithreading
//
// hook function for TNntp...
//
//
{
const char *p, name[FILENAME_MAX];
int num, cnt;
#ifdef DEBUG_ALL
printfT( "XREF: '%s'\n",s );
#endif
//
// Skip the host field
//
p = strpbrk( s," \t" );
if (p == NULL)
return;
//
// Look through the rest of the fields
// (note: the %n does not count in the sscanf-result)
//
while (sscanfT(p,"%*[ \t]%[^ \t:]%*[ \t:]%d%n",name,&num,&cnt) == 2) {
#ifdef DEBUG_ALL
printfT( "xref: '%s' %d\n",name,num )